﻿using BoardBroker;
using ComLib.ComFun;
using ComUIControl;
using KWindow.KPageCore;
using KXmlUIControl;
using LogLib;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;

namespace IPCPages
{
    public delegate void UpdateProgramStatus(string program, ProgramStartingStatus status, string msg);

    public delegate void AfterStartupFinishedHandler(AppsStartupResult result, List<KeyValuePair<string, string>> problems);
  
    public class Starter
    {
        private PageControlBase _pageControl = null;

        private List<XmlProgramObject> Programs = null;

        private List<KeyValuePair<string, string>> listProgramPath = new List<KeyValuePair<string, string>>();

        private List<KeyValuePair<string, string>> listProblems = new List<KeyValuePair<string, string>>();

        // 保存所有启动成功的进程列表
        private Dictionary<string, Process> _dicPrograms = new Dictionary<string, Process>();

        /// <summary>
        /// 指示子进程的状态，true:正常 false:未启动完成或已退出
        /// </summary>
        private ConcurrentDictionary<string, bool> _dicProgramStatus = new ConcurrentDictionary<string, bool>();

     
        /// <summary>
        /// 看护线程：检查子进程是否有退出，退出则重新启动进程
        /// </summary>
        private Thread _watchThread = null;

        /// <summary>
        /// 持续循坏看护子进程们的令牌
        /// </summary>
        private bool _watching = true;

        private const int Interval = 5000;

        /// <summary>
        /// 当前应用程序的主窗口句柄
        /// </summary>
        private IntPtr MainWindowHandle = IntPtr.Zero;

        private string StartupInfoArguments = "";

        /// <summary>
        /// 电机控制对象
        /// </summary>
        protected BoardControl _board = null;

        private AppsStartupResult _startupResult = AppsStartupResult.OK;
        public AppsStartupResult StartupResult
        {
            private set { _startupResult = value; }
            get { return _startupResult; }
        }

        public event UpdateProgramStatus ProgramStatusUpdated;
        public void OnMsgProgramStatusUpdated(string text, ProgramStartingStatus status, string msg)
        {
            if (ProgramStatusUpdated != null)
            {
                ProgramStatusUpdated(text, status, msg);
            }
        }

        public event AfterStartupFinishedHandler StartupFinished;
        protected void OnStartupFinished()
        {
            if (StartupFinished != null)
            {
                StartupFinished(StartupResult, listProblems);
            }
        }

        public PageConfigService _comService = null;

        public Starter(PageControlBase control, List<XmlProgramObject> list)
        {
            _pageControl = control;
            Programs = list;
            _comService = PageConfigService.Instance;
        }

        protected void InitMotion()
        {
            if (_pageControl.InvokeRequired)
            {
                Action handler = new Action(InitMotion);
                _pageControl.Invoke(handler, new object[] { });
                return;
            }
            if (!_board.FindLedControlWindowHandle())
            {
                Log.WriteAsync("未找到灯光控制程序!");
            }
            if (!_board.FindUSBControlWindowHandle())
            {
                Log.WriteAsync("未找到USB通断板控制程序!");
            }         
        }

        private void InitProgramStatus()
        {
            foreach(XmlProgramObject pro in Programs)
            {
                if (pro.Enable)
                {
                    _dicProgramStatus.TryAdd(pro.Name, false);
                }                
            }         
        }

        public void Init()
        {
            Log.WriteAsync("Init in");
            MainWindowHandle = Win32API.GetCurrentWindowHandle();
            Log.WriteAsync("当前应用程序窗口的句柄为:" + MainWindowHandle.ToString());
            _comService.InitPhotoNamingService();
            PipelinePool.MsgRecived += OnAppStartupFinished;
            CreatMotionControl();
            InitProgramStatus();
            StartExpecting();
            AsyncTask.StartDelayTask(1, StartPrograms, _pageControl);
            Log.WriteAsync("Init out");
        }

        /// <summary>
        /// 创建电机代理控制对象
        /// </summary>
        private void CreatMotionControl()
        {
            // 创建电机代理控制对象
            BoardControl.CreatInstance();
            _board = BoardControl.Instance;
        }
       
        private void CheckStartupCompleted()
        {           
            foreach (KeyValuePair<string, bool> p in _dicProgramStatus)
            {
                if (!p.Value)
                {
                    return;
                }
            }
            OnStartupFinished();
            if (_dicPrograms.ContainsKey("LedDemo"))
            {
                InitMotion();
            }            
            if (_startupResult == AppsStartupResult.OK)
            {            
                StartWatching();
            }
        }

        private void StartProgram(string prcName, string fileName)
        {
            ExitProcess(prcName);
            ProcessStartInfo Info = new ProcessStartInfo();
            Info.FileName = fileName;
            Info.CreateNoWindow = false;
            Info.WindowStyle = ProcessWindowStyle.Hidden;
            Info.Arguments = StartupInfoArguments;
            Process pro = Process.Start(Info);
            if (_dicPrograms.ContainsKey(prcName))
            {
                _dicPrograms[prcName] = pro;
            }
            else
            {
                _dicPrograms.Add(prcName, pro);
            }
        }

        public bool CheckFileExists(out string msg)
        {
            msg = "";
            listProgramPath.Clear();
            foreach (XmlProgramObject p in Programs)
            {
                if (p.Enable)
                {
                    string fileName = Path.Combine(Application.StartupPath, p.StartupPath);
                    if (File.Exists(fileName))
                    {
                        listProgramPath.Add(new KeyValuePair<string, string>(p.Name, fileName));
                    }
                    else
                    {
                        msg = "程序文件不存在:" + fileName;
                        Log.WriteAsync(msg);
                        return false;
                    }
                }
            }
            return true;         
        }

        public void StartPrograms()
        {
            string msg = "";
            if (!CheckFileExists(out msg))
            {
                MsgBox.Show(msg);
                return;
            }
            StartupInfoArguments = MainWindowHandle.ToString() + " " + _board.ProxyWindowHandle.ToInt32().ToString();
            Log.WriteAsync("传入进程启动参数为:" + StartupInfoArguments);
            foreach (KeyValuePair<string, string> p in listProgramPath)
            {
                OnMsgProgramStatusUpdated(p.Key, ProgramStartingStatus.Loading, "正在加载中...");
                StartProgram(p.Key, p.Value);
            }         
        }

        public void OnAppExited(IntPtr hWnd)
        {
            PipelinePool.Exit();
            StopPrograms(hWnd);       
        }

        private void OnAppStartupFinished(string proName, int code, string msg)
        {
              _pageControl.Invoke(new ThreadStart(delegate
               {
                   _dicProgramStatus[proName] = true;
                   XmlProgramObject program = Programs.Find(r => r.Name.Equals(proName));
                   if (program == null)
                   {
                       return;
                   }
                   ProgramStartingStatus status = ProgramStartingStatus.StartOK;
                   if (code == 1)
                   {
                       status = ProgramStartingStatus.StartOK;
                   }
                   else
                   {
                       // 一旦被严重错误赋值，不再进行赋值
                       if (StartupResult != AppsStartupResult.FatalError)
                       {
                           if (program.Primary)
                           {
                               StartupResult = AppsStartupResult.FatalError;
                           }
                           else
                           {
                               StartupResult = AppsStartupResult.FatalError;
                           }
                       }                     
                       listProblems.Add(new KeyValuePair<string, string>(proName, msg));
                       status = ProgramStartingStatus.StartFailed;
                   }
                   OnMsgProgramStatusUpdated(proName, status, msg);
                   CheckStartupCompleted();                                      
               }));                    
        }

        private void StopPrograms(IntPtr hWnd)
        {
            _watching = false;
            Uninstaller uninstaller = new Uninstaller(Programs, _dicPrograms);
            uninstaller.Run(hWnd);
        }

        protected static void ExitProcess(string processName)
        {
            Process[] processes = Process.GetProcesses();
            foreach (Process p in processes)
            {
                try
                {
                    if (p.ProcessName.ToUpper() == processName.ToUpper())
                    {
                        Log.WriteAsync("进程" + processName + "已存在");
                        p.Kill();
                        p.WaitForExit();
                        p.Close();
                        Log.WriteAsync("进程" + processName + "已关闭");
                    }
                }
                catch (Exception ex)
                {
                    Log.WriteException(ex.ToString());
                }
            }
        }

        /// <summary>
        /// 重启模块应用程序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RestartTheProgram(string proName, Process p)
        {
            _pageControl.Invoke(new ThreadStart(delegate
                {
                    StartProgram(proName, p.StartInfo.FileName);
                }));            
        }

        private void WatchThreadFun()
        {
            while (_watching)
            {
                List<KeyValuePair<string, Process>> listProcess = _dicPrograms.ToList();
                foreach (KeyValuePair<string, Process> p in listProcess)
                {
                    if (!_watching)
                    {
                        return;
                    }
                    string proName = p.Key;
                    if (p.Value.HasExited)
                    { 
                        bool val =false;
                        _dicProgramStatus.TryRemove(proName, out val);
                        string info = string.Format("程序{0}已退出, 现在重新启动。", proName);
                        Log.WriteAsync(info);
                        RestartTheProgram(proName, p.Value);
                    }
                }
                Thread.Sleep(Interval);
            }                 
        }

        public void StartWatching()
        {
            if (_watchThread != null)
            {
                return;
            }
            _watchThread = new Thread(WatchThreadFun);
            _watchThread.IsBackground = true;
            _watchThread.Start();
        }

        public void StartExpecting()
        {
            PipelinePool.CreatePipeLineAsync();
        }
    }
}
